//////////////////////////////////////////////////////////////////////////////////
//	 Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#include <algorithm>
#include <wx/gbsizer.h>
#include <wx/statline.h>
#include <wx/textdlg.h>
#include "rcmdapp.h"
#include "mainwnd.h"
#include "searchpanel.h"
#include <wx/regex.h>

enum cPanelIDS
{
	cIDSearchCombo=13000,
	cIDSearchFieldsCombo,
	cIDSearchButton,
	cIDSearchNextButton,
	cIDClearButton,
	cIDFilterButton,
	cIDFilterSelectorCombo,

};


BEGIN_EVENT_TABLE(CSearchPanel, wxPanel)
	EVT_BUTTON(cIDSearchButton, CSearchPanel::OnSearch)
	EVT_BUTTON(cIDSearchNextButton, CSearchPanel::OnSearchNext)
	EVT_BUTTON(cIDClearButton, CSearchPanel::OnClear)
	EVT_TEXT(cIDSearchCombo, 	CSearchPanel::OnSearchChanged)
	EVT_TEXT(cIDSearchFieldsCombo, 	CSearchPanel::OnSearchChanged)

	EVT_BUTTON(cIDFilterButton, CSearchPanel::OnFilterCfg)
	EVT_TEXT(cIDFilterSelectorCombo, 	CSearchPanel::OnFilterChanged)
END_EVENT_TABLE()

CSearchPanel::CSearchPanel(wxWindow* parent, ISearchProvider*	pSearchProv):wxPanel(parent),
	m_pSearch(pSearchProv), m_nCurSearchPos(0)
{
	wxBoxSizer* pSizer = new wxBoxSizer(wxHORIZONTAL);
	
	wxSizer* pSearch = CreateSearch();
	pSizer->Add(pSearch, 0, wxALL|wxALIGN_LEFT, 10); 

	InitSearchFields();

	if ( pSearchProv->HasFilter() )
	{
		pSizer->AddStretchSpacer();

		wxSizer* pFilter = CreateFilter();
		pSizer->Add(pFilter, 0, wxALL|wxALIGN_RIGHT, 10); 

		Load();
	}

	SetSizer(pSizer);
	
	pSizer->FitInside(this);
}

CSearchPanel::~CSearchPanel(void)
{
}

void CSearchPanel::Save()
{
	wxGetApp().GetMainWnd()->GetPropStorage().SetSearchFilters( m_pSearch->GetID(), m_filters );
}

void CSearchPanel::Load()
{
	m_filters = wxGetApp().GetMainWnd()->GetPropStorage().GetSearchFilters( m_pSearch->GetID() );

	m_pcFilterSelector->Clear();
	m_pcFilterSelector->Append(_("Not Filtered"), NOT_FILTERED);
	m_pcFilterSelector->SetSelection(0);

	for (FILTERS::iterator iCur = m_filters.begin();
		iCur != m_filters.end();iCur++)
	{
		int nID = m_pcFilterSelector->Append( iCur->strFilterName, FILTERED);

		if ( iCur->bActive) m_pcFilterSelector->Select(nID);
	}
}


wxSizer* CSearchPanel::CreateSearch()
{
	wxBoxSizer* pSizer = new wxBoxSizer(wxHORIZONTAL);

	int nFlags=wxLEFT|wxALIGN_CENTRE_VERTICAL;
	int nBorder=5;

	pSizer->Add(new wxStaticText(this, wxID_ANY, _("Find:")), 0, nFlags, nBorder);

	m_pcSearch = new wxComboBox(this, cIDSearchCombo );
	pSizer->Add(m_pcSearch, 0, nFlags, nBorder);

	pSizer->Add(new wxStaticText(this, wxID_ANY, _("in:")), 0, nFlags, nBorder);

	m_pcSearchFields = new wxComboBox(this, cIDSearchFieldsCombo, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxCB_READONLY );
	pSizer->Add(m_pcSearchFields, 0, nFlags, nBorder);

	m_pSearchButton = new wxButton(this, cIDSearchButton, _("Search"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxBU_EXACTFIT );
	pSizer->Add(m_pSearchButton, 0, nFlags, nBorder);

	m_pSearchNextButton = new wxButton(this, cIDSearchNextButton, _("Next"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxBU_EXACTFIT );
	m_pSearchNextButton->Enable(false);
	pSizer->Add(m_pSearchNextButton, 0, nFlags, nBorder);

	m_pSearchClearButton = new wxButton(this, cIDClearButton, _("Clear"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxBU_EXACTFIT );
	m_pSearchClearButton->Enable(false);
	pSizer->Add(m_pSearchClearButton, 0, nFlags, nBorder);

	return pSizer;
}

wxSizer* CSearchPanel::CreateFilter()
{
	wxBoxSizer* pSizer = new wxBoxSizer(wxHORIZONTAL);

	int nFlags=wxLEFT|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT;
	int nBorder=5;

	m_pFilterButton = new wxButton(this, cIDFilterButton, _("Filter"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER|wxBU_EXACTFIT );
	pSizer->Add(m_pFilterButton, 0, nFlags, nBorder);

	m_pcFilterSelector = new wxComboBox(this, cIDFilterSelectorCombo, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxCB_READONLY );
	pSizer->Add(m_pcFilterSelector, 0, nFlags, nBorder);

	return pSizer;
}

void CSearchPanel::InitSearchFields()
{
	assert(m_pSearch);
	assert(m_pcSearchFields);

	if ( m_pSearch && m_pcSearchFields )
	{
		SEARCHFIELD* sf;
		size_t sz=0;

		m_pSearch->GetSearchFields(sf, sz);

		m_pcSearchFields->Append(_("All"), (void*)SEARCH_FIELD_ANY);

		for (size_t i=0;i<sz;i++)
		{
			m_pcSearchFields->Append(sf[i].strLabel , (void*)sf[i].iFieldID);
		}

		m_pcSearchFields->SetSelection(0);
	}
}

int CSearchPanel::GetCurrentSearchField()
{
	int nRes(SEARCH_FIELD_ANY);

	assert(m_pcSearchFields);

	if ( m_pcSearchFields )
	{
		void* pData = m_pcSearchFields->GetClientData( m_pcSearchFields->GetCurrentSelection() );
		nRes = (int)pData;
	}

	return nRes;
}

void CSearchPanel::AddValueToVocablry(const wxString& strSearch)
{
	if (wxNOT_FOUND == m_pcSearch->FindString( strSearch ) )
	{
		m_pcSearch->Append(strSearch);
		m_pSearchClearButton->Enable();
	}
}

void CSearchPanel::ClearVocablry()
{
	m_pcSearch->Clear();
	m_pSearchClearButton->Enable(false);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Filter Logic
bool CSearchPanel::GetRuleSet(const wxString& strRuleName, FIELDRULESET& rlSet) const
{
	for( size_t i=0;i<m_filters.size();i++ )
	{
		if ( strRuleName == m_filters[i].strFilterName )
		{
			rlSet = m_filters[i].filterDef;

			return true;
		}
	}

	assert(false);

	return false;
}

bool  CSearchPanel::ApplyRule(const FILTERFIELDRULE& rule, const SEARCHFIELD& sf, const wxString& strVal) const
{
	bool bRes(true);

	switch( rule.rule )
	{
		case cFilterRuleAny:
		break;
			
		case cFilterRuleBigger:
			bRes = strVal>rule.strVal;
		break;

		case cFilterRuleBiggerOrEq:
			bRes = strVal>=rule.strVal;
		break;

		case cFilterRuleEq:
			bRes = strVal==rule.strVal;
			bRes|= strVal.Matches(rule.strVal);
		break;

		case cFilterRuleNotEq:
			bRes = strVal!=rule.strVal;
			bRes&= !strVal.Matches(rule.strVal);
		break;

		case cFilterRuleSmaller:
			bRes = strVal<rule.strVal;
		break;

		case cFilterRuleSmallerOrEq:
			bRes = strVal<=rule.strVal;
		break;

		case cFilterRuleRegExp:
		{
			wxRegEx regexp(rule.strVal, wxRE_DEFAULT);
			bRes = regexp.Matches(strVal);
		}
		break;
	}

	return bRes;
}

bool CSearchPanel::Match(const SEARCHFIELD& sf, const wxString& strVal) const
{
	bool bRes(true);

	try
	{
		if ( FILTERED == m_pcFilterSelector->GetClientData( m_pcFilterSelector->GetCurrentSelection()) )
		{
			FIELDRULESET rlSet;
			if ( GetRuleSet(m_pcFilterSelector->GetValue(), rlSet) )
			{
				for ( size_t i=0;i<rlSet.size();i++ )
				{
					if ( sf.iFieldID == rlSet[i].iFieldID )
					{
						bRes = ApplyRule(rlSet[i], sf, strVal);
						break;
					}
				}
			}
		}
	}
	catch(...)
	{
	}

	return bRes;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Events: Search
void CSearchPanel::OnSearchChanged(wxCommandEvent& ev)
{
	assert(m_pSearchNextButton);

	m_pSearchNextButton->Enable(false);
	m_nCurSearchPos = 0;

}

int	 CSearchPanel::DoSearch(const wxString& val, unsigned int iFieldID, size_t posStart)
{
	return m_pSearch->Search(val, iFieldID, posStart);
}

void CSearchPanel::OnSearch(wxCommandEvent& ev)
{
	assert(m_pSearch);
	assert(m_pcSearchFields);
	assert(m_pSearchNextButton);
	assert(m_pcSearch);

	m_pSearchNextButton->Enable(false);
	m_nCurSearchPos = 0;

	int nField = GetCurrentSearchField();
	wxString strSearch = m_pcSearch->GetValue();

	int nRes = DoSearch(strSearch, nField, m_nCurSearchPos);

	if ( SEARCH_NOT_FOUND == nRes )
	{
		wxMessageBox(_("Not Found!"), _("Error"),
		                         wxICON_INFORMATION | wxOK, this);
	}
	else
	{
		m_nCurSearchPos = nRes;
		m_pSearchNextButton->Enable();

		AddValueToVocablry(strSearch);
	}
}

void CSearchPanel::OnSearchNext(wxCommandEvent& ev)
{
	assert(m_pSearch);
	assert(m_pcSearchFields);
	assert(m_pSearchNextButton);
	assert(m_pcSearch);

	int nField = GetCurrentSearchField();

	wxString strSearch = m_pcSearch->GetValue();

	int nRes = DoSearch(strSearch, nField, 1+m_nCurSearchPos);

	if ( SEARCH_NOT_FOUND == nRes )
	{
		nRes = DoSearch(strSearch, nField, 0);
	}

	if ( SEARCH_NOT_FOUND == nRes )
	{
		wxMessageBox(_("Not Found!"), _("Error"),
		                         wxICON_INFORMATION | wxOK, this);

		m_pSearchNextButton->Enable(false);
	}
	else
	{
		m_nCurSearchPos = nRes;
	}
}

void CSearchPanel::OnClear(wxCommandEvent& ev)
{
	ClearVocablry();
}

void CSearchPanel::SetDefaultFilter()
{
	wxString strCurFilter = m_pcFilterSelector->GetValue();

	for (FILTERS::iterator iCur = m_filters.begin();
		iCur != m_filters.end();iCur++)
	{
		if ( strCurFilter == iCur->strFilterName )
		{
			iCur->bActive = true;
		}
		else
			iCur->bActive = false;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Events: Search
bool FilterSort(const FILTER& a, const FILTER& b)
{
	return a.strFilterName<b.strFilterName;
}

void CSearchPanel::OnFilterCfg(wxCommandEvent& ev)
{
	assert(m_pSearch);

	FILTERS	filters = m_filters;
	CFilterManager dlg(this, m_pSearch, filters);

	wxString strLastUsedFilter = m_pcFilterSelector->GetValue();

	if ( dlg.ShowModal() == wxID_OK )
	{
		std::sort(filters.begin(), filters.end(), FilterSort);

		m_filters = filters;

		Save();

		//Reload Filter
		Load();

		wxString strCurFilter = m_pcFilterSelector->GetValue();

		int nPos = m_pcFilterSelector->FindString(strLastUsedFilter);

		if (wxNOT_FOUND!=nPos)
			m_pcFilterSelector->Select(nPos);

		m_pSearch->OnFilterChanged();
		SetDefaultFilter();
	}
}

void CSearchPanel::OnFilterChanged(wxCommandEvent& ev)
{
	m_pSearch->OnFilterChanged();
	SetDefaultFilter();
	Save();
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////
//CFilterManager
enum cIDS
{
	cIDFilterAdd=13100,
	cIDFilterRemove,
	cIDFilterCombo,
	cIDFilterRuleComboBase=15000,
	cIDFilterRuleValBase=15100,
};

//wxEVT_COMMAND_TEXT_UPDATED

BEGIN_EVENT_TABLE(CFilterManager, wxDialog)
	EVT_BUTTON(cIDFilterAdd,	CFilterManager::OnAdd)
	EVT_BUTTON(cIDFilterRemove, CFilterManager::OnRemove)
	EVT_TEXT(cIDFilterCombo, 	CFilterManager::OnFilterSelected)
	EVT_COMMAND_RANGE(cIDFilterRuleComboBase, cIDFilterRuleComboBase+10, wxEVT_COMMAND_TEXT_UPDATED, CFilterManager::OnRuleUpdated)
	EVT_COMMAND_RANGE(cIDFilterRuleValBase, cIDFilterRuleValBase+10, wxEVT_COMMAND_TEXT_UPDATED, CFilterManager::OnRuleValUpdated) 
END_EVENT_TABLE()


CFilterManager::CFilterManager(wxWindow* parent, ISearchProvider* pSearch, FILTERS& filters):
	wxDialog(parent, wxID_ANY, _("Filter configuration"), wxDefaultPosition ),
	m_pSearch(pSearch), m_filters(filters)
{
	m_pSearch->GetSearchFields(m_sf, m_sz);

	wxBoxSizer* pBoxSizer = new wxBoxSizer(wxVERTICAL);

	wxGridBagSizer *pGrid = new wxGridBagSizer(10, 10);

	int nFlags=wxALL|wxALIGN_CENTER|wxEXPAND;

	m_pRemoveButton = new wxButton(this, cIDFilterRemove, _("Remove"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER );
	m_pcFilterSelCombo = new wxComboBox(this, cIDFilterCombo, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxCB_READONLY|wxCB_SORT );
	m_pAddButton = new wxButton(this, cIDFilterAdd, _("Add"), wxDefaultPosition, wxDefaultSize, wxNO_BORDER );

	pGrid->Add(m_pRemoveButton, 	wxGBPosition(0,0), wxDefaultSpan, nFlags);
	pGrid->Add(m_pcFilterSelCombo, 	wxGBPosition(0,1), wxDefaultSpan, wxALL|wxALIGN_CENTER);
	pGrid->Add(m_pAddButton, 		wxGBPosition(0,2), wxDefaultSpan, nFlags);

	pGrid->Add(10,10,wxGBPosition(1,0), wxGBSpan(1,3), nFlags);

	pGrid->Add(new wxStaticText(this, wxID_ANY, _("Column:")), 	wxGBPosition(2,0), wxDefaultSpan, 0);
	pGrid->Add(new wxStaticText(this, wxID_ANY, _("Rule:")), 	wxGBPosition(2,1), wxDefaultSpan, wxALIGN_CENTER_HORIZONTAL);
	pGrid->Add(new wxStaticText(this, wxID_ANY, _("Value:")),	wxGBPosition(2,2), wxDefaultSpan, wxALIGN_CENTER_HORIZONTAL);

	pGrid->Add(new wxStaticLine(this,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxLI_HORIZONTAL),	wxGBPosition(3,0), wxGBSpan(1,3), nFlags);

	int nRowCount=4;
	AddRuleTable(pGrid, nRowCount);

	wxSizer* sz = CreateStdDialogButtonSizer(wxOK|wxCANCEL);
	pGrid->Add(sz, 		wxGBPosition(nRowCount,0), wxGBSpan(1,3), nFlags);

	pBoxSizer->Add(pGrid, 1, wxALL|wxALIGN_CENTER|wxEXPAND, 20);

	SetSizer(pBoxSizer);

	pBoxSizer->Fit(this);

	LoadFilters();

	m_pcFilterSelCombo->SetSelection(0);

	RefreshFilter();
}

void CFilterManager::AddRuleTable(class wxGridBagSizer *pGrid, int& nRowCount)
{
	int nFlags=wxALL|wxALIGN_CENTER|wxEXPAND;

	m_ppRuleCombos = new wxComboBox*[m_sz];
	m_ppRuleValues = new wxTextCtrl*[m_sz];

	for (size_t i=0;i<m_sz;i++, nRowCount++)
	{
		pGrid->Add(new wxStaticText(this, wxID_ANY, m_sf[i].strLabel), wxGBPosition(nRowCount,0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);

		m_ppRuleCombos[i] = new wxComboBox(this, cIDFilterRuleComboBase+i, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxCB_READONLY );
		pGrid->Add(m_ppRuleCombos[i], wxGBPosition(nRowCount,1), wxDefaultSpan, wxALIGN_CENTER_HORIZONTAL);

		m_ppRuleCombos[i]->Append(_("Any"),		(void*)cFilterRuleAny);
		m_ppRuleCombos[i]->Append(_("="),		(void*)cFilterRuleEq);
		m_ppRuleCombos[i]->Append(_("<>"),		(void*)cFilterRuleNotEq);
		m_ppRuleCombos[i]->Append(_(">"),		(void*)cFilterRuleBigger);
		m_ppRuleCombos[i]->Append(_("<"),		(void*)cFilterRuleSmaller);
		m_ppRuleCombos[i]->Append(_(">="),		(void*)cFilterRuleBiggerOrEq);
		m_ppRuleCombos[i]->Append(_("<="),		(void*)cFilterRuleSmallerOrEq);
		m_ppRuleCombos[i]->Append(_("RegExp"),	(void*)cFilterRuleRegExp);
		m_ppRuleCombos[i]->SetSelection(0);
		//m_ppRuleCombos[i]->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxTextEventHandler(CFilterManager::OnRuleUpdated));

		m_ppRuleValues[i] = new wxTextCtrl(this, cIDFilterRuleValBase+i, wxT("") );
		pGrid->Add(m_ppRuleValues[i],	wxGBPosition(nRowCount,2), wxDefaultSpan, nFlags);
		m_ppRuleValues[i]->Enable(false);
		//m_ppRuleValues[i]->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxTextEventHandler(CFilterManager::OnRuleValUpdated));
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Logic
void CFilterManager::LoadFilters()
{
	for (FILTERS::iterator iCur = m_filters.begin();
		iCur != m_filters.end();iCur++)
	{
		if (!iCur->bSysDef)
			m_pcFilterSelCombo->Append( iCur->strFilterName );
	}
}

void CFilterManager::RemoveFilter(const wxString& strFilterName)
{
	for (FILTERS::iterator iCur = m_filters.begin();
		iCur != m_filters.end();iCur++)
	{
		if ( strFilterName == iCur->strFilterName )
		{
			m_filters.erase(iCur);
			break;
		}
	}
}

bool CFilterManager::GetFilter(const wxString& strName, FIELDRULESET& rSet)
{
	bool bRes(false);

	for (size_t i=0;i<m_filters.size();i++)
	{
		if ( 0==m_filters[i].strFilterName.CmpNoCase(strName) )
		{
			bRes = true;
			rSet = m_filters[i].filterDef;
			break;
		}
	}

	return bRes;
}

bool CFilterManager::GetRule(unsigned int iFieldID, const FIELDRULESET& rSet, FILTERFIELDRULE& rule)
{
	bool bRes(false);

	rule.iFieldID = iFieldID;
	rule.rule = cFilterRuleAny;

	for (size_t i=0;i<rSet.size();i++)
	{
		if ( iFieldID==rSet[i].iFieldID )
		{
			bRes = true;
			rule = rSet[i];
			break;
		}
	}

	return bRes;
}

void CFilterManager::ShowFilter(const wxString& strName)
{
	FIELDRULESET rSet;

	if ( GetFilter(strName, rSet) )
	{
		int nIdx = m_pcFilterSelCombo->FindString(strName);

		if (wxNOT_FOUND!=nIdx)
		{
			m_pcFilterSelCombo->Enable(true);
			m_pcFilterSelCombo->SetSelection(nIdx);
			
			m_pRemoveButton->Enable(true);
			EnableFilterFieids();
			ShowFilterFields(rSet);

		}
		else
		{
			m_pRemoveButton->Enable(false);
			EnableFilterFieids(false);
		}
	}
	else
	{
		m_pcFilterSelCombo->Enable(false);
		m_pRemoveButton->Enable(false);
		EnableFilterFieids(false);
	}
}

void CFilterManager::ShowFilterFields(FIELDRULESET& rSet)
{
	for (size_t i=0;i<m_sz;i++)
	{
		FILTERFIELDRULE rule;

		if ( GetRule(i, rSet, rule) )
		{
			SelectItem( m_ppRuleCombos[i], rule.rule);
			m_ppRuleValues[i]->SetValue( rule.strVal );
		}
		else
		{
			SelectItem( m_ppRuleCombos[i], cFilterRuleAny );
			m_ppRuleValues[i]->SetValue( wxT("") );
		}

		m_ppRuleValues[i]->Enable(cFilterRuleAny != rule.rule);
	}
}

void CFilterManager::EnableFilterFieids(bool bEnable)
{
	for (size_t i=0;i<m_sz;i++)
	{
		m_ppRuleCombos[i]->Enable(bEnable);
		m_ppRuleValues[i]->Enable(bEnable);
	}
}

void CFilterManager::RefreshFilter()
{
	wxCommandEvent ev;
	OnFilterSelected(ev);
}

void CFilterManager::SelectItem( class wxComboBox* pBox, cFilterRule	rule)
{
	assert(pBox);

	for (unsigned int i=0;i< pBox->GetCount();i++)
	{
		void *p = pBox->GetClientData(i);

		if ( (int)p==rule )
		{
			pBox->Select(i);
			break;
		}
	}
}

bool CFilterManager::GetCurRule(unsigned int iFieldID, FILTERFIELDRULE& rule)
{
	bool bRes(false);

	wxString strFilterName = m_pcFilterSelCombo->GetStringSelection();

	 FIELDRULESET rSet;

	if ( GetFilter(strFilterName, rSet) )
	{
		bRes = GetRule(iFieldID, rSet, rule);
	}

	return bRes;
}

void CFilterManager::SetCurRule( FILTERFIELDRULE& rule )
{ 
	wxString strFilterName = m_pcFilterSelCombo->GetStringSelection();

	for (size_t i=0;i<m_filters.size();i++)
	{
		if ( 0==m_filters[i].strFilterName.CmpNoCase(strFilterName) )
		{
			size_t j=0;
			FIELDRULESET&	filterDef = m_filters[i].filterDef;
			for (j=0;j<filterDef.size();j++)
			{
				if ( filterDef[j].iFieldID==rule.iFieldID)
				{
					filterDef[j].rule = rule.rule;
					filterDef[j].strVal = rule.strVal;
					break;
				}
			}

			if ( j==filterDef.size() )
			{
				filterDef.push_back( rule );
			}
			break;
		}
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Events
void CFilterManager::OnAdd(wxCommandEvent& ev)
{
	FIELDRULESET rSet;
	wxString strName = wxGetTextFromUser(_("Filter Name"));

	if ( strName.IsEmpty() )
	{
		wxMessageBox(_("Empty filter name!"), _("Error"),
	                         wxICON_WARNING | wxOK, this);
	}
	else 
	if (  GetFilter(strName, rSet) )
	{
		wxMessageBox(_("Filter name already exist!"), _("Error"),
	                         wxICON_WARNING | wxOK, this);
	}
	else
	{
		FILTER filter;
		filter.strFilterName = strName;
		
		m_filters.push_back(filter);

		m_pcFilterSelCombo->Append(strName);
		ShowFilter(strName);
	}
}

void CFilterManager::OnRemove(wxCommandEvent& ev)
{
	int nSel = m_pcFilterSelCombo->GetCurrentSelection();

	if ( wxNOT_FOUND!=nSel )
	{
		wxString strFilterName = m_pcFilterSelCombo->GetStringSelection();
		m_pcFilterSelCombo->Delete(nSel);
		RemoveFilter(strFilterName);
	}

	m_pcFilterSelCombo->SetSelection(0);
	RefreshFilter();
}

void CFilterManager::OnFilterSelected(wxCommandEvent& ev)
{
	wxString strFilterName = m_pcFilterSelCombo->GetStringSelection();
	ShowFilter( strFilterName );
}

void CFilterManager::OnRuleUpdated(wxCommandEvent& ev)
{
	int nIDX = ev.GetId() - cIDFilterRuleComboBase;
	int nSel = m_ppRuleCombos[nIDX]->GetSelection();
	int iFieldID = m_sf[nIDX].iFieldID;

	if ( wxNOT_FOUND!=nSel )
	{
		void* p = m_ppRuleCombos[nIDX]->GetClientData(nSel);
		cFilterRule	rule = (cFilterRule)(int)p;

		FILTERFIELDRULE ruleFF;
		GetCurRule(iFieldID, ruleFF);
		ruleFF.rule = rule;
		SetCurRule(ruleFF);

		FILTERFIELDRULE ruleFF2;
		GetCurRule(iFieldID, ruleFF2);
		assert(ruleFF.rule==ruleFF2.rule);

		m_ppRuleValues[nIDX]->Enable(cFilterRuleAny != rule);
	}
}

void CFilterManager::OnRuleValUpdated(wxCommandEvent& ev)
{
	int nIDX = ev.GetId() - cIDFilterRuleValBase;
	wxString strVal = m_ppRuleValues[nIDX]->GetValue();
	int iFieldID = m_sf[nIDX].iFieldID;

	FILTERFIELDRULE ruleFF;
	GetCurRule(iFieldID, ruleFF);

	ruleFF.strVal = strVal;
	SetCurRule(ruleFF);

	FILTERFIELDRULE ruleFF2;
	GetCurRule(iFieldID, ruleFF2);
	assert(ruleFF.strVal==ruleFF2.strVal);
}

